package preprocessor.absorption;

//import java.util.HashMap;
import java.util.HashSet;

import option.KBVocabulary;
//import java.util.Map;

//import utils.exception.AbsorptionException;
import utils.exception.ConceptException;

import entities.axiom.InclusionAxiom;
import entities.concept.AndConcept;
//import entities.concept.AtomicConcept;
import entities.concept.Concept;
//import entities.concept.Nominal;
import entities.concept.NotConcept;
import entities.concept.OrConcept;
import entities.concept.PConcept;
import kb.TBox;

public class BinaryAbsorption implements Absorption {
	private TBox tbox;

	public BinaryAbsorption(TBox tb) {
		this.tbox = tb;
	}

	public boolean absorb() {
		boolean suc = true;
		if (this.tbox.getTg().size() > 0) {
			// try to absorb each GCI
			for (Concept c : this.tbox.getTg().keySet()) {
				InclusionAxiom ax = new InclusionAxiom(c, this.tbox.getTg()
						.get(c));
				suc = suc && absorbAxiom(ax);
			}
		}
		return suc;
	}

	/**
	 * Absorb a single axiom for A /\ B -> C
	 * 
	 * @param ax
	 * @return
	 */
	public boolean absorbAxiom(InclusionAxiom ax) {
		boolean abs = false;
		Concept lhs = ax.getLHS();
		if (lhs.isBinarySimple()) {
			// a and b -> c
			AndConcept ac = (AndConcept) lhs;
			try {
				this.tbox.insertTb(ac.getConceptSet(), ax.getRHS());
				abs = true;
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			// convert axiom into top->{a set of disjuncts}
			HashSet<Concept> ors = new HashSet<Concept>();
			ors.add(new NotConcept(lhs));
			ors.add(ax.getRHS());
			OrConcept gen = new OrConcept(ors);
			abs = absorbAxiom(Concept.reduceToDisjuncts(gen));
		}

		return abs;

	}

	// if the axiom is given as a set of disjuncts, only consider ~a, ~b, etc.
	public boolean absorbAxiom(HashSet<Concept> ax) {
		boolean abs = false;
		HashSet<Concept> todo = new HashSet<Concept>();
		HashSet<Concept> remain = new HashSet<Concept>();
		remain.addAll(ax);
		for (Concept c : ax) {
			if (c.isSimpleNot()) {
				NotConcept nc = (NotConcept) c;
				remain.remove(c);
				todo.add(nc.getConcept());
				if (todo.size() == 2) {
					break;
				}
			}
		}
		if (todo.size() != 2) {
			return false;
		}
		PConcept fresh = PConcept.newInternalPConcept();
		remain.add(new NotConcept(fresh));
		try {
			this.tbox.insertTb(todo, fresh);
			abs = true;
		} catch (ConceptException e) {
			e.printStackTrace();
		}
		// add the new axiom back
		this.tbox.saveGeneratedGCIs(KBVocabulary.CONCEPT_TOP, new OrConcept(
				remain));
		return abs;
	}

}
